﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

using MefContrib.Hosting.Generics;

namespace NuMetaheuristics.Utility
{
    /// <summary>
    /// This class is used to discover all of the algorithms which can be used
    /// for the given genotype.
    /// </summary>
    /// <typeparam name="G">The genotype class which inherits from IGenotype.</typeparam>
    public class AlgorithmDiscoverer<G>
        where G : IGenotype
    {
        [Export]
        private class AlgorithmCatalog
        {
            [ImportMany]
            public IEnumerable<IAlgorithm<G>> Algorithms { get; set; }

            override public string ToString()
            {
                string output = string.Format("Context Catalog: {0} entries\n", Algorithms.Count());
                foreach (IAlgorithm<G> item in Algorithms)
                {
                    output += string.Format(" -{0}\n", item.GetType().Name);
                }
                output += "\n";

                return output;
            }
        }

        /// <summary>
        /// Uses all of the exported IGenericContractRegistry classes to search
        /// for algorithms which can be used for the given genotype.
        /// </summary>
        /// <returns>A list of the algorithms which can be used for the given genotype.</returns>
        public List<Type> DiscoverAlgorithmTypes()
        {
            List<IGenericContractRegistry> contractRegistries = new Discoverer<IGenericContractRegistry>().DiscoverObjects();

            var typeCatalog = new TypeCatalog(typeof(AlgorithmCatalog));
            var genericCatalog = new GenericCatalog(contractRegistries.ToArray());
            var aggregateCatalog = new AggregateCatalog(typeCatalog, genericCatalog);
            var container = new CompositionContainer(aggregateCatalog);
                
            var catalog = container.GetExportedValue<AlgorithmCatalog>();
            
            var types = new List<Type>();

            foreach (IAlgorithm<G> algorithm in catalog.Algorithms)
            {
                types.Add(algorithm.GetType());
            }

            return types;
        }
    }
}
